<?php

namespace App\Service\VendorClient\Shopwangdtqjb;

use App\Service\Code\Normal;
use App\Service\BaseService;
use App\Model\PssModel\ServiceConfig;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;

/**
 * 旺店通(旗舰版)上游对接(一般贸易)SDK
 * @author hj
 */
class ShopwangdtqjbApiClient extends BaseService {
    //供应商编号
    const SUPPLIER_CODE = 'shopwangdtqjb';

    //配置文件
    private $config = [];

    public function __construct($apiBody = []) {
        $this->config           = $apiBody;
        $arr                    = explode(':', $this->config['appSecret'], 2);
        $this->config['secret'] = $arr[0];
        $this->config['salt']   = $arr[1];
    }

    /**
     * 创建订单
     * @param array $params
     * @return array
     */
    public function createOrder($param = []) {
        if (empty($param['supplierOrder']) || empty($param['orderGoods']) || empty($param['order']) || empty($param['binfo'])) {
            return Normal::returnCode(Normal::FAIL, "except param supplierOrder or orderGoods or order or binfo");
        }
        $orderInfo = $param['supplierOrder'];
        $goodsList = $param['orderGoods'];
        $order     = $param['order'];
        $binfo     = $param['binfo'];
        $order_sn  = $orderInfo['supplier_dsn'];
        //订单时间
        $order_time = $orderInfo['cd'] ? date('Y-m-d H:i:s', $orderInfo['cd']) : date('Y-m-d H:i:s', time());
        //支付时间
        $pay_time = isset($order['payTime']) && !empty($order['payTime']) ? date('Y-m-d H:i:s', $order['payTime']) : date('Y-m-d H:i:s', time());
        //运费分摊
        $deliver_money = $orderInfo['deliver_money'];
        //优惠
        $discount_money = $orderInfo['discount_money'];
        //下单支付的时候支付信息
        $apply_extends = @json_decode($orderInfo['apply_extends'], true);
        //获取下单商品信息
        $orderGoodsList   = [];
        $goodsMoneyOrigin = 0;
        foreach ($goodsList as $v) {
            $goodsMoneyOrigin = bcadd($goodsMoneyOrigin, bcmul($v['price'], $v['quantity'], 2), 2);
        }
        $hasDiscountMoney = $order_pay_amount = $channel_discount_amount = $goodsTotalMoney = 0;
        $goodsNum         = count($goodsList);
        $goodsToalQty     = 0;
        foreach ($goodsList as $key => $item) {
            $price            = (string)$item['price'];
            $spec_num         = (string)$item['spec_num'];
            $quantity         = (string)$item['quantity'];
            $supplier_skucode = $item['supplier_skucode'];
            $goods_type       = $item['goods_type'];
            $buyNum           = $spec_num * $quantity;
            //分摊优惠金额到单个商品
            if ($key == $goodsNum - 1) {
                $skuDiscountAmountTotal = bcsub((string)$discount_money, (string)$hasDiscountMoney, 2);
            } else {
                $singleGoodsTotalPrice  = bcmul((string)$price, (string)$quantity, 2);
                $scale                  = bcdiv((string)$singleGoodsTotalPrice, (string)$goodsMoneyOrigin, 4);
                $skuDiscountAmountTotal = bcmul((string)$scale, (string)$discount_money, 2);
                $hasDiscountMoney       = bcadd((string)$hasDiscountMoney, (string)$skuDiscountAmountTotal, 2);
            }
            //原始销售单价
            $singlePrice = bcdiv((string)$price, (string)$spec_num, 3);
            $singlePrice = ceil(bcmul((string)$singlePrice, '100', 1));
            $singlePrice = bcdiv((string)$singlePrice, '100', 2);
            //向上取整3位收上去的
            $singleNewTotalPrice = bcmul((string)$singlePrice, (string)$buyNum, 2);
            $signleOldTotalPrice = bcmul((string)$price, (string)$quantity, 2);
            $diff_price          = bcsub((string)$singleNewTotalPrice, (string)$signleOldTotalPrice, 2);
            //优惠金额还需要加上补差金额否则无法过去
            $skuDiscountAmountTotal = bcadd((string)$diff_price, (string)$skuDiscountAmountTotal, 2);
            //单个商品实际支付总金额
            $sku_pay_amount = bcsub((string)$singleNewTotalPrice, (string)$skuDiscountAmountTotal, 2);
            //根据goods_no和spec_no查询goods_id和spec_id
            $goodsRes = $this->queryGoodsDetail(['goods_no' => trim($item['supplier_commodity_key']), 'spec_no' => trim($item['supplier_skucode'])]);
            if ($goodsRes['code'] != Normal::SUC) {
                return Normal::returnCode(Normal::FAIL, '下单商品查询失败：' . $goodsRes['msg']);
            }
            $goodsRaw = $goodsRes['data'];
            //下单商品组
            $goodsInfo               = [
                'tid'            => $order_sn,//指商城、官网等平台的订单编号，ERP称之为原始单号
                'oid'            => $item['id'],//平台订单货品表主键,子订单唯一标识
                'status'         => 30,//平台子订单状态，子订单状态可以和主订单不一样可选值同trade_status
                'refund_status'  => 0,//0:无退款,1:取消退款,2:已申请退款,3:等待退货,4:等待收货,5:退款成功
                'goods_id'       => $goodsRaw['goods_id'],//平台系统货品（SPU）的唯一标识。goods_id不能为空
                'spec_id'        => $goodsRaw['spec_id'],//平台系统单品（SKU）的的唯一标识。SPU和SKU概念介绍
                'goods_no'       => trim($item['supplier_commodity_key']),//货品编号
                'spec_no'        => trim($item['supplier_skucode']),//规格编码
                'goods_name'     => $item['goods_name'],//名称
                'num'            => $buyNum,//货品数量
                'price'          => $singlePrice,//单价
                'discount'       => 0,//优惠，平台折扣, 不包含手工调整和分摊优惠
                'share_discount' => $skuDiscountAmountTotal,//分摊优惠,退款不变
                'total_amount'   => $singleNewTotalPrice,//总价格 total_amount=price*num+adjust_amount-discount
                'adjust_amount'  => 0,//手工调整的优惠金额，
                'refund_amount'  => 0,//退款金额
                'remark'         => '',//备注
                'json'           => '',//json串，若无可传“”
            ];
            $orderGoodsList[]        = $goodsInfo;
            $goodsTotalMoney         = bcadd((string)$goodsTotalMoney, (string)$singleNewTotalPrice, 2);
            $channel_discount_amount = bcadd((string)$channel_discount_amount, (string)$skuDiscountAmountTotal, 2);
            $goodsToalQty            += $buyNum;
        }
        //用户实际支付金额
        $real_total_money = $orderInfo['real_total_money'];
        //订单总价（商品保税价格 + 运费） 暂时不这样计算
        $totalMoney       = bcadd((string)$goodsTotalMoney, (string)$deliver_money, 2);//分摊计算出来的订单总金额
        $order_pay_amount = bcsub((string)$totalMoney, (string)$channel_discount_amount, 2);//实际支付总金额;
        if ($order_pay_amount != $real_total_money) {
            return Normal::returnCode(Normal::FAIL, "金额分摊计算有误");
        }
        $orderList[] = [
            'tid'              => $order_sn,//指商城、官网等平台的订单编号，ERP称之为原始单号
            'process_status'   => 30,//是否执行自动递交以系统配置为准10: 待递交, 20: 已递交，30: 部分发货，40: 已发货，60: 已完成，70: 已取消
            'trade_status'     => 30,//0未确认 20待尾款 30待发货 40部分发货 50已发货 60已签收 70已完成 80已退款 90已关闭(付款前取消)
            'refund_status'    => 0,//0无退款 1申请退款 2部分退款 3全部退款
            'pay_status'       => 2,//0未付款1部分付款2已付款
            'order_count'      => $goodsNum,//原始单包含的子订单数，rawTradeOrderList节点下所有子单数之和
            'goods_count'      => $goodsToalQty,//货品总数量，rawTradeOrderList节点下所有“num”数量之和
            'pay_method'       => 8,//1在线转帐 2现金，3银行转账，4邮局汇款 5预付款 6刷卡 7支付宝 8微信支付
            'trade_time'       => $order_time,//平台订单创建时间,时间格式：yyyy-MM-dd HH:mm:ss
            'pay_time'         => $pay_time,//平台订单付款时间,时间格式：yyyy-MM-dd HH:mm:ss，未付款订单为:0000-00-00 00:00:00
            'end_time'         => null,//交易结束时间，若无则传null
            'buyer_nick'       => $orderInfo['buyer_realname'],//平台买家昵称，注意：一次推送网名相同的订单不能超过30
            'buyer_message'    => $orderInfo['order_remark'] ?? '',//若无则传‘’
            'receiver_name'    => $orderInfo['receive_name'],//收件人姓名
            'receiver_area'    => $orderInfo['province'] . ' ' . $orderInfo['city'] . ' ' . $orderInfo['district'],//省市区空格分隔，示例【北京 北京市 朝阳区】，省市区推送旺店通地址库
            'receiver_address' => $orderInfo['receive_address'],//收件人详细地址，不包含省市区，示例【xx街道xx小区xx号楼101】
            'receiver_mobile'  => $orderInfo['recveive_phone'],//该字段必传，收件人手机号，为11位手机号码，示例【13888888888】
            'post_amount'      => $deliver_money,//邮费
            'discount'         => $channel_discount_amount,//优惠金额
            'receivable'       => $real_total_money,//应收金额，售前退款会变化 receivable=∑(total_amount-share_discount)+post_amount,
            'delivery_term'    => 1,//1:款到发货,2:货到付款(包含部分货到付款),3:分期付款,4:挂账
            'remark'           => $orderInfo['order_remark'] ?? '',//客服备注
            'is_auto_wms'      => false,//true自流转，false 非自流转  自动流转模式处理办法详解
            'warehouse_no'     => '',//仅自流转订单填写该仓库编号, 非自流转订单传入空字符串即可
        ];
        $data        = [
            'method' => 'createOrder',
            'data'   => [
                $this->config['shopNo'],
                $orderList,
                $orderGoodsList
            ],
        ];
        $pushRes     = $this->execute($data);
        if ($pushRes['code'] != Normal::SUC) {
            return $pushRes;
        }
        //错误信息为空，表示全部创建成功
        if (isset($pushRes['data']['data']['error_list']) && !empty($pushRes['data']['data']['error_list'])) {
            return Normal::returnCode(Normal::FAIL, '订单推送失败：' . json_encode($pushRes['data'], 320), $pushRes['data']);
        }
        return $pushRes;
    }

    /**
     * 查询商品详情
     * ['goods_no' => trim($item['supplier_commodity_key']), 'spec_no' => trim($item['supplier_skucode'])]
     * @param $param
     * @return array
     */
    public function queryGoodsDetail($param) {
        $data   = [
            'method' => 'queryGoods',
            'data'   => [[
                'spec_no'      => $param['spec_no'],
                'goods_no'     => $param['goods_no'],
                'hide_deleted' => 1,//0:返回全部;1:隐藏已删除   默认隐藏
            ]],
            'pager'  => [
                'page_size'  => 10,
                'page_no'    => 0,
                'calc_total' => 1,//是否计算查询结果的总条数, 需要计算则1, 否则填0
            ]
        ];
        $result = $this->execute($data);
        if ($result['code'] != Normal::SUC) {
            return $result;
        }
        $goodsList = $result['data']['data']['goods_list'] ?? [];
        if (!$goodsList) {
            return Normal::returnCode(Normal::FAIL, '获取商品失败1：' . json_encode($result['data'], 320), $result['data']);
        }
        $goodsByGoodsNo = array_column($goodsList, null, 'goods_no');
        $spuArr         = $goodsByGoodsNo[$param['goods_no']] ?? [];
        if (!$spuArr) {
            return Normal::returnCode(Normal::FAIL, '获取商品失败2：' . json_encode($result['data'], 320), $result['data']);
        }
        $specArr = $spuArr['spec_list'] ?? [];
        if (!$specArr) {
            return Normal::returnCode(Normal::FAIL, '获取商品失败3：' . json_encode($result['data'], 320), $result['data']);
        }
        $specBySpecNo = array_column($specArr, null, 'spec_no');
        $goods        = $specBySpecNo[$param['spec_no']] ?? [];
        if (!$goods) {
            return Normal::returnCode(Normal::FAIL, '获取商品失败4：' . json_encode($result['data'], 320), $result['data']);
        }
        return Normal::returnCode(Normal::SUC, "操作成功", $goods);
    }

    /**
     * 申请退款接口
     * @param $data
     * @return array
     */
    public function orderAfterSale($params = []) {
        $goodsList   = $params['orderGoods'];
        $refundGoods = [];
        //订单状态（0-待付款，1-已付款，2-已发货，100-已取消，200-支付失败）
        $orderStatus = $params['supplierOrder']['order_status'];
        //优惠
        $discount_money   = $params['supplierOrder']['discount_money'];
        $type             = $orderStatus != 2 ? 1 : 2;
        $goodsMoneyOrigin = 0;
        foreach ($goodsList as $v) {
            $goodsMoneyOrigin = bcadd($goodsMoneyOrigin, bcmul($v['price'], $v['quantity'], 2), 2);
        }
        $goodsNum         = count($goodsList);
        $hasDiscountMoney = $order_pay_amount = $channel_discount_amount = $goodsTotalMoney = 0;
        foreach ($goodsList as $key => $item) {
            $price            = (string)$item['price'];
            $spec_num         = (string)$item['spec_num'];
            $quantity         = (string)$item['quantity'];
            $supplier_skucode = $item['supplier_skucode'];
            $goods_type       = $item['goods_type'];
            $buyNum           = $spec_num * $quantity;
            //分摊优惠金额到单个商品
            if ($key == $goodsNum - 1) {
                $skuDiscountAmountTotal = bcsub((string)$discount_money, (string)$hasDiscountMoney, 2);
            } else {
                $singleGoodsTotalPrice  = bcmul((string)$price, (string)$quantity, 2);
                $scale                  = bcdiv((string)$singleGoodsTotalPrice, (string)$goodsMoneyOrigin, 4);
                $skuDiscountAmountTotal = bcmul((string)$scale, (string)$discount_money, 2);
                $hasDiscountMoney       = bcadd((string)$hasDiscountMoney, (string)$skuDiscountAmountTotal, 2);
            }
            //原始销售单价
            $singlePrice = bcdiv((string)$price, (string)$spec_num, 3);
            $singlePrice = ceil(bcmul((string)$singlePrice, '100', 1));
            $singlePrice = bcdiv((string)$singlePrice, '100', 2);
            //向上取整3位收上去的
            $singleNewTotalPrice = bcmul((string)$singlePrice, (string)$buyNum, 2);
            $signleOldTotalPrice = bcmul((string)$price, (string)$quantity, 2);
            $diff_price          = bcsub((string)$singleNewTotalPrice, (string)$signleOldTotalPrice, 2);
            //优惠金额还需要加上补差金额否则无法过去
            $skuDiscountAmountTotal = bcadd((string)$diff_price, (string)$skuDiscountAmountTotal, 2);
            //单个商品实际支付总金额
            $sku_pay_amount = bcsub((string)$singleNewTotalPrice, (string)$skuDiscountAmountTotal, 2);

            $refundGoods[] = [
                'refund_no'             => 'TK' . $params['supplierOrder']['supplier_dsn'],//平台退款/退货单单号，保证唯一
                'num'                   => $buyNum,//货品数量
                'tid'                   => $params['supplierOrder']['supplier_dsn'],
                'oid'                   => $item['id'],
                // 'type' => $type,//0取消订单1退款(未发货，退款申请)2退货3换货4退款不退货
                'type'                  => 1,//0取消订单1退款(未发货，退款申请)2退货3换货4退款不退货
                'status'                => 2,//1取消退款,2已申请退款,3等待退货,4等待收货,5退款成功
                'refund_version'        => '1',//退款版本，默认传1即可
                'refund_amount'         => $singleNewTotalPrice,//申请退款金额
                'actual_refund_amount'  => $singleNewTotalPrice,//实际退款金额
                'title'                 => $item['goods_name'],//标题，对应原始退款单页面主单货品字段
                'logistics_name'        => '',//物流公司名称（支持自定义推送）
                'logistics_no'          => '',//物流单号
                'buyer_nick'            => $params['supplierOrder']['buyer_realname'],//客户网名
                'refund_time'           => date('Y-m-d H:i:s'),//退款创建时间
                'current_phase_timeout' => date('Y-m-d H:i:s'),//退款成功时间
                'is_aftersale'          => 0,//是否售后退款单
                'reason'                => $params['order']['exceptReason'] ?? '人工运营处理售后退款',//退款原因
            ];
        }
        $data    = [
            'method' => 'orderAfterSale',
            'data'   => [
                $this->config['shopNo'],
                $refundGoods,
            ],
        ];
        $pushRes = $this->execute($data);
        if ($pushRes['code'] != Normal::SUC) {
            return $pushRes;
        }
        //错误信息为空，表示全部创建成功
        if (isset($pushRes['data']['data']['error_list']) && !empty($pushRes['data']['data']['error_list'])) {
            return Normal::returnCode(Normal::FAIL, '售后订单推送失败：' . json_encode($pushRes['data'], 320), $pushRes['data']);
        }
        return $pushRes;
    }

    /**
     * 查询物流
     * @param $OrderSupplier
     * @return array
     */
    public function queryOrderExpress($OrderSupplier) {
        $orderSn = $OrderSupplier['supplier_dsn'];
        $data    = [
            'method' => 'orderExpress',
            'data'   => [[
                'shop_no'         => $this->config['shopNo'],
                'is_own_platform' => true,//是否自有平台（自有平台调用传true）是：true  否：false不填默认为false
                'tid'             => $orderSn,//原始单号
            ]],
            'pager'  => [
                'page_size'  => 100,
                'page_no'    => 0,
                'calc_total' => 1,//是否计算查询结果的总条数, 需要计算则1, 否则填0
            ]
        ];
        $result  = $this->execute($data);
        if ($result['code'] != Normal::SUC) {
            return $result;
        }
        $tradeList = $result['data']['data'] ?? [];
        if (empty($tradeList)) {
            return Normal::returnCode(Normal::FAIL, '未查询到物流信息1', $result);
        }
        $tradeListByTid = array_column($tradeList, NULL, 'tid');
        $targetArr      = $tradeListByTid[$orderSn] ?? [];
        if (empty($targetArr)) {
            return Normal::returnCode(Normal::FAIL, '未查询到物流信息2', $result);
        }
        //查到了就去回传
        // $this->orderExpressAck([$targetArr['sync_id']]);//sync_id
        return Normal::returnCode(Normal::SUC, "获取成功", $targetArr);
    }

    /**
     * 物流成功回传
     * @param $syncIds
     * @return array
     */
    public function orderExpressAck($syncIds = []) {
        if (!$syncIds) {
            return Normal::returnCode(Normal::FAIL, '缺少sync_id参数');
        }
        $ackList = [];
        foreach ($syncIds as $sync_id) {
            $ackList[] = [
                'sync_id'   => $sync_id,//回写的记录id，见logistics_sync_query中rec_id
                'status'    => 0,//0: 同步成功、-100: 还需同步，2:同步失败
                'error_msg' => "",//失败的错误信息，若成功传“”
            ];
        }
        $data = [
            'method' => 'orderExpressAck',
            'data'   => [
                $ackList
            ],
        ];
        return $this->execute($data);
    }

    /**
     * 签名
     * @param $data
     * @return string
     */
    public function sign($data) {
        ksort($data);
        $arr   = array();
        $arr[] = $this->config['secret'];
        foreach ($data as $key => $val) {
            if ($key == 'sign') continue;
            $arr[] = $key;
            $arr[] = $val;
        }
        $arr[] = $this->config['secret'];
        return md5(implode('', $arr));
    }

    /**
     * CURL请求
     * @param $params
     * @return array
     */
    public function execute($param = []) {
        $method = $param['method'];
        $pager  = $param['pager'] ?? [];
        if (!isset($this->config[$method])) {
            return Normal::returnCode(Normal::FAIL, "请求路由未设置");
        }
        if (empty($param['data'])) {
            return Normal::returnCode(Normal::FAIL, "数据不能为空");
        }
        $baseUrl = $this->config['baseUrl'] ?? '';
        if (empty($baseUrl)) {
            return Normal::returnCode(Normal::FAIL, "接口请求地址不能为空");
        }
        $commonParam              = [];
        $commonParam['sid']       = $this->config['sid'];
        $commonParam['key']       = $this->config['appkey'];
        $commonParam['salt']      = $this->config['salt'];
        $commonParam['method']    = $this->config[$method];
        $commonParam['timestamp'] = time() - 1325347200;//秒级时间戳, 当前时间戳减去 2012-01-01 00:00:00(1325347200), 时间与服务器时间差120s内即合法。
        $commonParam['v']         = $this->config['version'];
        if ($pager) {
            $commonParam['page_size']  = $pager['page_size'];
            $commonParam['page_no']    = $pager['page_no'];
            $commonParam['calc_total'] = $pager['calc_total'];
        }
        $commonParam['body'] = json_encode($param['data']);
        $commonParam['sign'] = $this->sign($commonParam);
        unset($commonParam['body']);
        $url       = $this->config['baseUrl'] . '?' . http_build_query($commonParam);
        $parameter = [
            [
                'tag'    => self::SUPPLIER_CODE . '_' . $param['method'],
                'uid'    => IdService::instance()->getOtherID(),
                'url'    => $url,
                'data'   => $param['data'],
                'method' => 'post',
                'format' => 'json',
                'header' => [],
            ],
        ];
        // $resTask          = TaskWorker::instance()->addTask($parameter);
        if (in_array($param['method'], ['orderExpress', 'orderExpressAck', 'queryGoods'])) {
            $resTask = TaskWorker::instance()->addTask($parameter, 'handleDiableTask');
        } else {
            $resTask = TaskWorker::instance()->addTask($parameter);
        }
        $resTask = current($resTask);
        $result  = @json_decode($resTask['response']['result'], true);
        if (isset($result['status']) && $result['status'] == 0) {
            return Normal::returnCode(Normal::SUC, "操作成功", $result);
        }
        $msg = $result['message'] ?? '请求失败';
        return Normal::returnCode(Normal::FAIL, $msg, $result);
    }
}